package com.joyintech.config;

import com.joyintech.annotation.Dict;
import com.joyintech.modules.system.service.dto.DictDetailDto;
import com.joyintech.modules.system.service.mapper.DictDetailMapper;
import com.joyintech.utils.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.*;

/**
 * 入参拦截器
 * @program: eladmin
 * @description:
 * @author: daiweiwei@joyintech.com
 * @create: 2022-03-13 14:41
 */

@Slf4j
@Intercepts({@Signature(type = ParameterHandler.class, method = "setParameters", args = PreparedStatement.class)})
@Component
public class ParammeterInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if (invocation.getTarget() instanceof ParameterHandler) {
            log.info("ParameterHandler:setParameters 拦截器处理字典值到落标值映射...");
            ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();
            MetaObject metaObject = MetaObject.forObject(parameterHandler, SystemMetaObject.DEFAULT_OBJECT_FACTORY, SystemMetaObject.DEFAULT_OBJECT_WRAPPER_FACTORY, new DefaultReflectorFactory());
            MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("mappedStatement");
            if (mappedStatement.getSqlCommandType() != SqlCommandType.INSERT && mappedStatement.getSqlCommandType() != SqlCommandType.UPDATE) return invocation.proceed();
            Class<?> beanClass  = Class.forName(mappedStatement.getParameterMap().getType().getName());
            if(beanClass==null) return invocation.proceed();
            Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
            parameterField.setAccessible(true);
            Object parameterObject = parameterField.get(parameterHandler); // 取出实例(参数实例)
            if(parameterObject ==null) return invocation.proceed();
            Arrays.asList(beanClass.getDeclaredFields())
                    .stream()
                    .filter(field ->Objects.nonNull(AnnotationUtils.findAnnotation(field, Dict.class) ))
                    .forEach(field ->  update(metaObject,parameterObject,field) );
        }
        return invocation.proceed();
    }

    private void update(MetaObject metaObject,Object parameterObject, Field field) {
        Dict dictClass = AnnotationUtils.findAnnotation(field, Dict.class);
        if(!dictClass.mark()) return;
        String key = field.getName(); //status
        // 集合 param1 kw 两个是通过对象
        try{
        if (parameterObject instanceof MapperMethod.ParamMap) {
            Set keySet = ((MapperMethod.ParamMap)parameterObject).keySet();
            Iterator iterator = keySet.iterator();
            while (iterator.hasNext()) {
                Object target = ((MapperMethod.ParamMap) parameterObject).get(iterator.next());
                Field targetField = Arrays.stream(target.getClass().getDeclaredFields()).filter(f -> f.getName().equals(key)).findAny().orElse(null);
                if(targetField==null) continue;
                targetField.setAccessible(true);
                DictDetailDto dictDetail = getDictDetail(dictClass.dict(), String.valueOf(targetField.get(target)));
                targetField.set(target,dictDetail.getMark());
                break;
            }
            metaObject.setValue("parameterObject", parameterObject);
        }}catch (Exception e){}
    }

    @Override
    public Object plugin(Object o) {
        return Plugin.wrap(o, this);
    }

    @Override
    public void setProperties(Properties properties) {
        System.out.println("----------");

    }
    private DictDetailDto getDictDetail(String dictName,String value){
        DictDetailMapper dictDetailMapper = SpringContextHolder.getBean(DictDetailMapper.class);
        List<DictDetailDto> ret = dictDetailMapper.getDictDetailsByDictName(dictName);
        if(Objects.isNull(ret)) return null;
        return  ret.stream().filter(dto -> dto.getValue().equals(value)).findAny().orElse(new DictDetailDto());
    }

}
